<!--
 Copyright (c) 2023, donnie <donnie4w@gmail.com>
 All rights reserved.
 Use of this source code is governed by a BSD-style
 license that can be found in the LICENSE file.

 github.com/donnie4w/webtim
-->
<html lang="en">

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link href="/assets/plugins/perfect-scrollbar/css/perfect-scrollbar.css" rel="stylesheet">
	<link href="/assets/plugins/metismenu/css/metisMenu.min.css" rel="stylesheet">
	<link rel="shortcut icon" href="/favicon.ico">
	<link rel="bookmark" href="/favicon.ico">
	<script src="/assets/js/bootstrap.bundle.min.js"></script>
	<script src="/assets/js/jquery.min.js"></script>
	<script src="/assets/js/t.js"></script>
	<script src="/assets/plugins/perfect-scrollbar/js/perfect-scrollbar.js"></script>
	<link href="/assets/css/bootstrap.min.css" rel="stylesheet">
	<link href="/assets/css/app.css" rel="stylesheet">
	<link href="/assets/css/icons.css" rel="stylesheet">
	<link rel="stylesheet" href="/assets/css/dark-theme.css">
	<link rel="stylesheet" href="/assets/css/semi-dark.css">
	<link rel="stylesheet" href="/assets/css/header-colors.css">
	<title>webtim</title>
</head>

<body>
	<div class="top-menu ms-auto">
		<ul class="navbar-nav align-items-center">
			<li class="nav-item dropdown dropdown-large">
				<div class="dropdown-menu dropdown-menu-end">
					<div class="header-notifications-list">
					</div>
				</div>
			</li>
			<li class="nav-item dropdown dropdown-large">
				<div class="dropdown-menu dropdown-menu-end">
					<div class="header-message-list">
					</div>
				</div>
			</li>
		</ul>
	</div>
	<div class="wrapper">
		<div class="page-content">
			<div class="col-lg-12 card p-lg-1 ">
				<div class="page-content">
					<div class="chat-wrapper">
						<div class="chat-sidebar">
							<div class="chat-sidebar-header">
								<div class="d-flex align-items-center">
									<div class="chat-user-online" onclick="hideSidebar()">
										<img src="/img/user.png" id="icon" width="45" height="45" class="rounded-circle"
											alt="">
									</div>
									<div class="flex-grow-1 ms-2" onclick="hideSidebar()">
										<p class="mb-0" id="loginflag">未登录</p>
									</div>
								</div>
								<div class="mb-3"></div>
								<div class="input-group input-group-sm">
									<input type="text" class="form-control" placeholder="用户名" id="username">
									<input type="password" class="form-control" placeholder="密码" id="pwd">
									<span onclick="login()"><button type="button" class="btn btn-primary">登录
										</button></span>
								</div>
							</div>
							<div class="chat-sidebar-content">
								<div class="tab-content" id="pills-tabContent">
									<div class="tab-pane fade show active" id="pills-Chats">
										<div class="chat-list ps ps--active-y">
											<div class="list-group list-group-flush" id="friends">
											</div>
											<div class="ps__rail-x" style="left: 0px; bottom: -232px;">
												<div class="ps__thumb-x" tabindex="0" style="left: 0px; width: 0px;">
												</div>
											</div>
											<div class="ps__rail-y" style="top: 232px; height: 300px; right: 0px;">
												<div class="ps__thumb-y" tabindex="0"
													style="top: 131px; height: 168px;"></div>
											</div>
										</div>
									</div>
								</div>
							</div>
						</div>
						<div class="chat-header d-flex align-items-center">
							<div class="chat-toggle-btn"><i class="bx bx-menu-alt-left"></i>
							</div>

							<div class="input-group mb-2"><span class="input-group-text"
									onclick="hideSidebar()">对方账号</span><input type="text" class="form-control"
									placeholder="账号" id="accountId"></div>
							<div>
								<h4 class="mb-1 font-weight-bold" style="word-break:keep-all" id="usertitle">您未登录</h4>
							</div>
							<div>
								<h4 class="mb-1 font-weight-bold"><img src="/img/user.png" id="icontitle" width="60"
										height="60" class="rounded-circle"></h4>
							</div>
						</div>
						<div class="chat-content ps ps--active-y" id="containerId">
							<div class="ps__rail-x" style="left: 0px; bottom: 0px;">
								<div class="ps__thumb-x" tabindex="0" style="left: 0px; width: 0px;"></div>
							</div>
							<div class="ps__rail-y" style="top: 0px; height: 520px; right: 0px;">
								<div class="ps__thumb-y" tabindex="0" style="top: 0px; height: 235px;"></div>
							</div>
						</div>
						<div class="chat-footer d-flex align-items-center">
							<div class="flex-grow-1 pe-2">
								<div class="input-group">
									<input type="text" class="form-control" placeholder="Enter your message" id="msgid">
								</div>
							</div>
							<div class="chat-footer-menu1">
								<button type="button" class="btn btn-facebook" onclick="send()">Send
								</button>
							</div>
						</div>
						<!--start chat overlay-->
						<div class="overlay chat-toggle-btn-mobile"></div>
						<!--end chat overlay-->
					</div>
				</div>
			</div>
		</div>
		<div class="overlay toggle-icon"></div>
		<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
	</div>
	<script>
		new PerfectScrollbar('.chat-list');
		new PerfectScrollbar('.chat-content');
	</script>
	<script src="assets/js/app.js"></script>
	<script src="assets/js/timjs.js"></script>
	<script>
		var tc = new timClient(false, "192.168.2.11", 5120);
		var myAccount = "";
		var hight = 0;
		//ack message from server 服务反馈的信息
		tc.ackHandler = function (data) {
			console.log(data);
			let ta = new TimAck();
			ta = JSON.parse(data);
			switch (ta.timType) {
				case STAT.TIMMESSAGE:
					if (ta.ok) { //not ok 表示信息发送失败(注意，信息发送成功是没有ack的，服务器会推送发送用户的信息回来，信息会带上时间与id)
						console.log("send message failed>>", ta.error.code, ":", ta.error.info);
					}
					break;
				case STAT.TIMPRESENCE:
					if (ta.ok) { //not ok，表示状态信息发送失败(注意，状态信息发送成功是没有ack的)
						console.log("send presence failed>>", ta.error.code, ":", ta.error.info);
					}
					break;
				case STAT.TIMLOGOUT: // 强制下线
					console.log("force to logout >>>", myAccount);
					tc.Logout(); // 收到强制下线的指令后，主动退出登录
					break;
				case STAT.TIMAUTH:
					if (ta.ok) { // 登录成功
						myAccount = ta.n;
						console.log("login successful,my node is :", myAccount);
						online(myAccount);
					} else {
						console.log("login failed:", ta.error.code, ":", ta.error.info);
						tc.Logout();
						console.log("login failed and logout");
						if (ta.error.code == STAT.ERR_AUTH) {
							alert("用户名密码错误");
						} else if (ta.error.code == STAT.ERR_OVERENTRY) {
							alert("同账号登录超过限制数");
						} else {
							alert("登录失败");
						}
						initloginflag(false, "");
					}
					break;
				/*************************************************************/
				case STAT.TIMBUSINESS: //业务操作回馈
					if (ta.ok) {
						console.log("business process ok:", ta.n);
						switch (ta.t) {
							case STAT.BUSINESS_REMOVEROSTER: //删除好友成功
								console.log("romove friend successful:", ta.n);
								break;
							case STAT.BUSINESS_BLOCKROSTER: //拉黑好友成功
								console.log("block  successful:", ta.n);
								break;
							case STAT.BUSINESS_NEWROOM: //新建群组成功
								console.log("new group successful:", ta.n);
								break;
							case STAT.BUSINESS_ADDROOM: //
								console.log("join group successful:", ta.n);
							case STAT.BUSINESS_PASSROOM: //申请加入群成功
								console.log("new group successful:", ta.n);
								break;
							case STAT.BUSINESS_NOPASSROOM: //申请加入群不成功
								console.log("reject  group successful:", ta.n);
								break;
							case STAT.BUSINESS_PULLROOM: //拉人入群
								console.log("new group successful:", ta.n);
								break;
							case STAT.BUSINESS_KICKROOM: //踢人出群
								console.log("kick out of group successful:", ta.n);
								break;
							case STAT.BUSINESS_BLOCKROOM:
								console.log("block the group successful:", ta.n)
								break;
							case STAT.BUSINESS_LEAVEROOM: //退群
								console.log("leave group successful:", ta.n);
								break;
							case STAT.BUSINESS_CANCELROOM: //注销群
								console.log("cancel group successful:", ta.n);
								break;
							default:
								console.log("business successful >>", ta);
						}
					} else {
						console.log("business process failed:", ta.error.code, ":", ta.error.info);
					}
					break;
				case STAT.TIMNODES:
					switch (ta.t) {
						case STAT.NODEINFO_MODIFYUSER:
							console.log("modify userinfo successful");
							break;
						case STAT.NODEINFO_MODIFYROOM:
							console.log("modify roominfo successful");
							break;
					}

			}
		};

		//TimMessage 处理handler
		tc.messageHandler = function (data) {
			let tm = new TimMessage();
			tm = JSON.parse(data);
			console.log(tm);
			//message消息
			if (tm.msType == 1) {
				console.log("this is system message >>", " body>>>", tm);
			} else if (tm.msType == 2) {
				console.log("this is user to user message");
			} else if (tm.msType == 3) {
				console.log("this is room to user message");
			}
			if (tm.msType != 1) {
				switch (tm.odType) {
					case 1: //常规消息
						console.log(tm.dataString);
						if (!isEmpty(tm.dataString)) {
							console.log("chat message >> from 111>>", tm.fromTid.node, " ,to>>", tm.toTid, ",body>>>", tm.dataString);
						}
						appendmsg(tm.fromTid.node, unixnanoToDatatime(tm.timestamp), tm.dataString);
						break;
					default: //开发者自定义的消息
						console.log("other message>>>", tm);
				}
			}

		};

		//记录状态订阅者
		var submap = {};
		//状态消息
		tc.presenceHandler = function (data) {
			let tp = new TimPresence()
			tp = JSON.parse(data);
			console.log(tp);
			if (!isEmpty(tp.subStatus)) {
				if (tp.subStatus == 1) {
					tc.PresenceToUser(tp.fromTid.node, 0, "😄", 2, null, null);
				}
				if (tp.subStatus == 1 || tp.subStatus == 2) {
					if (isEmpty(submap[tp.fromTid.node])) {
						submap[tp.fromTid.node] = 0;
					}
				}
			}
			if ((isEmpty(tp.offline)) && (tp.fromTid.node == myAccount)) {
				tc.BroadPresence(1, 0, "I am busy😄");
			}
			console.log("presence>>>", tp);
		};

		function online(account) {
			let cover = usericon(account)
			document.getElementById("icon").src = cover;
			document.getElementById("icontitle").src = cover;
			document.getElementById("friends").innerHTML = "";
			document.getElementById("containerId").innerHTML = "";
			initloginflag(true, account)
		}

		function failedSend(msg) {
			div.innerHTML =
				'<div class="chat-content-rightside"><div class="d-flex ms-auto"><div class="flex-grow-1 me-2">' +
				'<p class="mb-0 chat-time text-end">you, ' + datetime() +
				'</p><p class="chat-right-msg text-light">' + msg + '</p></div></div></div>';
			document.getElementById("containerId").appendChild(div);
		}

		function appendmsg(account, nanotime, msg) {
			let cover = usericon(account)
			if (account == myAccount) {
				var div = document.createElement('div');
				div.innerHTML =
					'<div class="chat-content-rightside"><div class="d-flex ms-auto"><div class="flex-grow-1 me-2">' +
					'<p class="mb-0 chat-time text-end">you, ' + nanotime + '</p><p class="chat-right-msg">' +
					msg + '</p></div></div></div>'
				document.getElementById("containerId").appendChild(div);
			} else {
				var div = document.createElement('div');
				div.innerHTML = '<a href="javascript:peer(\'' + account + '\');"><div class="chat-content-leftside"><div class="d-flex">' +
					'<img src="' + cover + '" width="48" height="48" class="rounded-circle" alt=""><div class="flex-grow-1 ms-2">' +
					'<p class="mb-0 chat-time"><B style="color:blue">' + account + "</B>," + nanotime +
					'</p><p class="chat-left-msg">' + msg + '</p></div></div></div></a>';
				document.getElementById("containerId").appendChild(div);

				if (!document.getElementById("f" + account)) {
					addfriendlist(account)
				}
			}
			hight = hight + 200;
			document.getElementById("containerId").scrollTo(0, document.documentElement.scrollHeight + hight);
			window.scrollTo(0, document.documentElement.scrollHeight);
		}

		function addfriendlist(account) {
			let cover = usericon(account)
			var div = document.createElement('div');
			var fs = '<a href="javascript:peer(\'' + account + '\');" class="list-group-item">'
				+ '<div class="d-flex">'
				+ '<div class="chat-user-online">'
				+ '<img src="' + cover + '" width="42" height="42" class="rounded-circle" alt="">'
				+ '</div>'
				+ '<div class="flex-grow-1 ms-2">'
				+ '<h6 class="mb-0 chat-title">' + account + '</h6>'
				+ '<p class="mb-0 chat-msg" style="font-size: smaller;">' + account + '</p>'
				+ '</div>'
				+ '<div class="chat-time">' + datetime() + '</div>'
				+ '</div>'
				+ '</a>';
			div.id = "f" + account;
			div.innerHTML = fs;
			document.getElementById("friends").appendChild(div);
		}

		function send() {
			let msg = document.getElementById("msgid").value;
			let node = document.getElementById("accountId").value;
			if (isEmpty(node)) {
				alert("请输入对方账号");
				return
			}
			try {
				if (!isEmpty(msg)) {
					tc.MessageToUser(node, msg, 0, 0);
				}
			} catch (err) {
				alert("信息发送失败");
				return
			}
			document.getElementById("msgid").value = "";
		}

		$("#msgid").keydown(function () {
			if (event.keyCode == "13") {
				send();
			}
		})

		function initloginflag(_login, name) {
			if (_login == false) {
				document.getElementById("loginflag").innerText = "未登录";
				document.getElementById("usertitle").innerText = "未登录";
				document.getElementById("icon").src = "/img/user.png";
				document.getElementById("icontitle").src = "/img/user.png";
			} else {
				document.getElementById("loginflag").innerText = "您已登录:" + name;
				document.getElementById("usertitle").innerText = "";
			}
		}

		function peer(a) {
			document.getElementById("accountId").value = a;
		}

		function login() {
			var username = document.getElementById("username").value;
			var pwd = document.getElementById("pwd").value;
			if (username == "" || pwd == "") {
				alert("用户名密码不能为空");
				return
			}
			//登录
			tc.Login(username, pwd, "tlnet.top", "web browser", 1);
			hideSidebar();
		}

		function hideSidebar() {
			$(".chat-wrapper").removeClass("chat-toggled")
		}

	</script>
	<script>
		function isEmpty(obj) {
			if (typeof obj == "undefined" || obj == null || obj == "") {
				return true;
			} else {
				return false;
			}
		}

		Date.prototype.Format = function (fmt) {
			var o = {
				"M+": this.getMonth() + 1,
				"d+": this.getDate(),
				"h+": this.getHours(),
				"m+": this.getMinutes(),
				"s+": this.getSeconds(),
				"q+": Math.floor((this.getMonth() + 3) / 3),
				"S": this.getMilliseconds()
			};
			if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
			for (var k in o)
				if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) :
					(("00" + o[k]).substr(("" + o[k]).length)));
			return fmt;
		}

		function datetime() {
			return new Date().Format("yyyy-MM-dd hh:mm:ss")
		}

		function unixnanoToDatatime(v) {
			let dt = new Date(v / 1000000);
			return dt.Format("yyyy-MM-dd hh:mm:ss");
		}

		function usericon(name) {
			const checksum = crc32(new TextEncoder().encode(name));
			return "/img/" + checksum % 30 + ".png"
		}

		const table = [];
		for (let i = 0; i < 256; i++) {
			let c = i;
			for (let j = 0; j < 8; j++) {
				if ((c & 1) === 1) {
					c = 0xEDB88320 ^ (c >>> 1);
				} else {
					c = c >>> 1;
				}
			}
			table[i] = c;
		}
		function crc32(data) {
			let crc = 0xFFFFFFFF;
			for (let i = 0; i < data.length; i++) {
				crc = table[(crc ^ data[i]) & 0xFF] ^ (crc >>> 8);
			}
			return (~crc >>> 0);
		}
	</script>
</body>

</html>